package models

import (
	valid "main/src/core"
	"sort"

	"gorm.io/gorm"
	"github.com/lib/pq"
)

type ES2Child struct {
	gorm.Model
	ES2ParentID      uint           `gorm:"unique,uniqueIndex"`
	NPC              string         `json:"npc" bson:"npc" gorm:"unique,uniqueIndex"`
	Name             string         `json:"name" bson:"name" gorm:"unique,uniqueIndex"`
	SNILS            string         `json:"-" bson:"-"`
	Birth            string         `json:"-" bson:"-"`
	ValidationResult pq.StringArray `gorm:"type:text[]" json:"valid_res" bson:"valid_res"`
}

type ES2Parent struct {
	gorm.Model
	ES2SchoolID      uint           `gorm:"unique,uniqueIndex"`
	Name             string         `json:"-" bson:"-" gorm:"unique,uniqueIndex"`
	SNILS            string         `json:"-" bson:"-"`
	Birth            string         `json:"-" bson:"-"`
	ES2Childs        []ES2Child     `json:"childs" bson:"childs" gorm:"foreignKey:ES2ParentID"`
	Valid            bool           `json:"valid" bson:"valid"`
	ValidationResult pq.StringArray `gorm:"type:text[]" json:"valid_res" bson:"valid_res"`
}

type ES2School struct {
	gorm.Model
	ES2PDChildsOtchetID uint        `gorm:"unique,uniqueIndex"`
	Name                string      `json:"name" bson:"name" gorm:"unique,uniqueIndex"`
	ES2Parents          []ES2Parent `json:"parents" bson:"parents" gorm:"foreignKey:ES2SchoolID"`
}

type ES2PDChildsOtchet struct {
	gorm.Model
	Name       string      `json:"name" bson:"name" gorm:"unique,uniqueIndex"`
	ES2Schools []ES2School `json:"schools" bson:"schools" gorm:"foreignKey:ES2PDChildsOtchetID"`
}

func (ES2PDChildsOtchet) LoadFromMap(data map[string]map[string][]string, headers map[string]string) (*ES2PDChildsOtchet, error) {
	otchet := ES2PDChildsOtchet{
		Name:       "Общие сведения об обучающихся",
		ES2Schools: make([]ES2School, 0),
	}

	for sch, data := range data {
		otchet.ES2Schools = append(otchet.ES2Schools, ES2School{Name: sch, ES2Parents: make([]ES2Parent, 0)})
		schindex := len(otchet.ES2Schools) - 1
		for i := 0; i < len(data["Name"]); i++ {
			parent := ES2Parent{
				Name:  data["PName"][i],
				SNILS: data["PSNILS"][i],
				Birth: data["PBirth"][i],
				ES2Childs: []ES2Child{{
					NPC:   data["NPC"][i],
					Name:  data["Name"][i],
					SNILS: data["SNILS"][i],
					Birth: data["Birth"][i],
				}},
			}
			if !parent.Validate() {
				otchet.ES2Schools[schindex].ES2Parents = append(otchet.ES2Schools[schindex].ES2Parents, parent)
			}
		}
	}

	return otchet.Save()
}

func (otchet *ES2PDChildsOtchet) compareES2Parents(otchet2 ES2PDChildsOtchet) bool {
	if len(otchet.ES2Schools) != len(otchet2.ES2Schools) || len(otchet.ES2Schools) == 0 {
		return false
	}

	// Сортировка коллекций ES2Schools перед сравнением
	sort.Slice(otchet.ES2Schools, func(i, j int) bool {
		return otchet.ES2Schools[i].ID < otchet.ES2Schools[j].ID // предположим, что ID используется для сравнения
	})
	sort.Slice(otchet2.ES2Schools, func(i, j int) bool {
		return otchet2.ES2Schools[i].ID < otchet2.ES2Schools[j].ID
	})
	for i := 0; i < len(otchet.ES2Schools) && i < len(otchet2.ES2Schools); i++ {
		if len(otchet.ES2Schools[i].ES2Parents) != len(otchet2.ES2Schools[i].ES2Parents) {
			return false
		}
	}
	return true
}

func (otchet *ES2PDChildsOtchet) Save() (*ES2PDChildsOtchet, error) {
	if otchetInDb, err := FetchES2PDChildsOtchetByName(otchet.Name); err == nil {
		if !otchetInDb.compareES2Parents(*otchet) {
			Database.Delete(&otchetInDb)
		}
	}

	if otchetInDb, err := FetchES2PDChildsOtchetByName(otchet.Name); err == nil {
		if err := otchetInDb.Update(otchet); err != nil {
			return nil, err
		}
		if otchetInDb, err := FetchES2PDChildsOtchetByName(otchet.Name); err == nil {
			return otchetInDb, nil
		} else {
			return nil, err
		}
	}
	err := Database.Model(&otchet).Create(&otchet).Error
	if err != nil {
		return &ES2PDChildsOtchet{}, err
	}
	return otchet, nil
}

func (parent *ES2Parent) Validate() bool {
	parent.Valid = true
	pErrors := make([]string, 0)
	cErrors := make([]string, 0)
	if !valid.IsValidSnils(parent.SNILS) {
		pErrors = append(pErrors, "СНИЛС заявителя не валиден.")
		parent.Valid = false
	}

	if parent.Birth == "1970-01-01" ||
		!valid.IsValidBirthDate(parent.Birth) {
			pErrors = append(pErrors, "Дата рождения заявителя не валидна.")
		parent.Valid = false
	}

	for i, child := range parent.ES2Childs {
		if !valid.IsValidSnils(child.SNILS) {
			cErrors = append(cErrors, "СНИЛС обучающегося не валиден.")
			parent.Valid = false
		}
		if child.Birth == "1970-01-01" ||
			!valid.IsValidBirthDate(child.Birth) {
				cErrors = append(cErrors, "Дата рождения обучающегося не валидна.")
			parent.Valid = false
		}
		parent.ES2Childs[i].ValidationResult = pq.StringArray(cErrors)
	} 
	parent.ValidationResult = pq.StringArray(pErrors)

	return parent.Valid
}

func FetchES2PDChildsOtchetById(id string) (*ES2PDChildsOtchet, error) {
	var otchet ES2PDChildsOtchet
	err := Database.Where("id = ?", id).First(&otchet).Error
	if err != nil {
		return &ES2PDChildsOtchet{}, err
	}
	return &otchet, nil
}

func FetchES2PDChildsOtchetByName(name string) (*ES2PDChildsOtchet, error) {
	var otchet ES2PDChildsOtchet
	err := Database.Preload("ES2Schools").Preload("ES2Schools.ES2Parents").Preload("ES2Schools.ES2Parents.ES2Childs").Where("name =?", name).First(&otchet).Error
	if err != nil {
		return &ES2PDChildsOtchet{}, err
	}
	return &otchet, nil
}

func (otchetInDb *ES2PDChildsOtchet) Update(otchet *ES2PDChildsOtchet) error {
	if err := Database.Transaction(func(tx *gorm.DB) error {
		if err := tx.Model(&ES2PDChildsOtchet{}).Where("name = ?", otchetInDb.Name).Updates(otchet).Error; err != nil {
			return err
		}

		// // Обновить связанные структуры
		// for i := range otchet.ES2Schools {
		// 	for j := range otchet.ES2Schools[i].ES2Parents {
		// 		if err := tx.Model(&ES2Parent{}).Where("id = ?", otchetInDb.ES2Schools[i].ES2Parents[j].ID).Updates(otchet.ES2Schools[i].ES2Parents[j]).Error; err != nil {
		// 			return err
		// 		}
		// 		for k := range otchet.ES2Schools[i].ES2Parents[j].ES2Childs {
		// 			if err := tx.Model(&ES2Child{}).Where("id = ?", otchetInDb.ES2Schools[i].ES2Parents[j].ES2Childs[k].ID).Updates(otchet.ES2Schools[i].ES2Parents[j].ES2Childs[k]).Error; err != nil {
		// 				return err
		// 			}
		// 		}
		// 	}
		// }

		return nil
	}); err != nil {
		return err
	}

	return nil
}

func (parent *ES2PDChildsOtchet) UpdateES2PDChildsOtchetById(id string) (*ES2PDChildsOtchet, error) {
	err := Database.Model(&ES2PDChildsOtchet{}).Where("id = ?", id).Updates(parent).Error

	if err != nil {
		return &ES2PDChildsOtchet{}, err
	}
	return parent, nil
}

func (parent *ES2PDChildsOtchet) UpdateES2PDChildsOtchetByName(name string) (*ES2PDChildsOtchet, error) {
	err := Database.Model(&ES2PDChildsOtchet{}).Where("name = ?", name).Updates(parent).Error

	if err != nil {
		return &ES2PDChildsOtchet{}, err
	}
	return parent, nil
}
